package gmu.swe.project.tracker;

import static java.util.concurrent.TimeUnit.SECONDS;
import gmu.swe.project.registry.RegistryInfo;
import gmu.swe.project.registry.RegistryServer;
import gmu.swe.project.registry.TrackerRegistration;
import gmu.swe.project.utils.Helper;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * A scheduled keep alive ping thread that will register the tracker the first
 * time and send subsequent keep alive pings to the registries at a scheduled
 * interval
 * 
 * 
 * @author Stacy Meyer
 * 
 */
public class KeepAlivePingThread extends Thread {
	
	int interval = 0;
	final static ScheduledExecutorService scheduler = Executors
			.newScheduledThreadPool(1);
	private static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
	static SimpleDateFormat dfm = new SimpleDateFormat(DATE_FORMAT_NOW);
	private ArrayList<RegistryInfo> registryServers = null;
	TrackerRegistration trackerRegistration = null;
	KeepAlivePingThread(int intervalArg, ArrayList<RegistryInfo> rs) {
		super("KeepAlivePingThread");
		this.interval = intervalArg;
		this.registryServers = rs;
	}// KeepAlivePingThread

	public void run() {

		System.out.println("KeepAlivePingThread::KeepAliveService thread spawned");

		pingRegistry();
	}// run
	
	/**
	 * 
	 */
	private void pingRegistry() {
		try {

			final Runnable keepAlivePing = new Runnable() {

				public void run() {
					Iterator<RegistryInfo> registryIter = registryServers
							.iterator();
					while (registryIter.hasNext()) {

						Date time = Helper.getCurrTime();
						System.out.println("KeepalivePingThread()::Current time: "
										+ dfm.format(time));
						System.out.println("KeepalivePingThread::Ping Registry (every "
										+ Integer.toString(interval) + " seconds)");
						try {
							RegistryInfo ri = (RegistryInfo) registryIter
									.next();
							String ip = ri.getIpAddress();
							Integer port = ri.getPort();

							Socket socketConnection = new Socket(ip, port);
//							System.out
//									.println("KeepalivePingThread::ip: " + ip);
//							System.out.println("KeepalivePingThread::port: "
//									+ port);
							// output stream to write to the server
							ObjectOutputStream clientOutputStream = new ObjectOutputStream(
									socketConnection.getOutputStream());

							// incoming stream to receive from the server
							ObjectInputStream clientInputStream = new ObjectInputStream(
									socketConnection.getInputStream());

							clientOutputStream.writeObject(Tracker.trackerInfo);

							trackerRegistration = (TrackerRegistration) clientInputStream
									.readObject();

							System.out.println("KeepalivePingThread()::trackerRegistration from server, size: "
											+ Integer.toString(trackerRegistration.getTrackerSet().size()));

							// Send the tracker registration back to the parent
							// tracker
							Tracker.trackerRegistration = trackerRegistration;

							// close the streams
							clientOutputStream.close();
							clientInputStream.close();
							socketConnection.close();

//							System.out
//									.println("KeepalivePingThread()::Client closed");
						} catch (Exception ex) {
							System.out.println("KeepalivePingThread::Exception thrown: "
											+ ex.toString());
						}// catch
					}// while
					System.out.println("KeepalivePingThread::Done sending keep alive message");
				}// run
			};
			scheduler.scheduleAtFixedRate(keepAlivePing, 1, interval, SECONDS);

		} catch (Exception ex) {
			System.out.println("KeepalivePingThread()::Error in KeepalivePingThread: "
							+ ex.toString());
		}
	}// pingRegistry

}// class KeepAlivePingThread(...
